package cn.sjxy.regi.service.impl;

import cn.sjxy.regi.dto.OrdersDto;
import cn.sjxy.regi.exception.CustomException;
import cn.sjxy.regi.mapper.OrdersMapper;
import cn.sjxy.regi.pojo.*;
import cn.sjxy.regi.service.*;
import cn.sjxy.regi.utils.BaseContext;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * ClassName:OrdersServiceImpl
 * Package:cn.sjxy.regi.service.impl
 * Description:
 *
 * @Date:2022/6/26 13:50
 * @Author:SXW
 */
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements OrdersService {

    @Autowired
    private ShoppingCartService shoppingCartService;

    @Autowired
    private UserService userService;

    @Autowired
    private AddressBookService addressBookService;

    @Autowired
    private OrderDetailService orderDetailService;

    /**
     * 功能：在跳转到个人中心时，查询到当前最新的订单数据
     * 需求：
     * 1. 获取到当前最新订单数据，按照下单时间排序
     * 2. 分页展示，当数量较多时，分页
     *
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public Page getPage(int page, int pageSize, String number, String beginTime, String endTime) {
        Page<Orders> pageInfo = new Page<>(page, pageSize);
        Page<OrdersDto> ordersDtoPage = new Page<>();
        LambdaQueryWrapper<Orders> lqw = new LambdaQueryWrapper<>();

        lqw.eq(StringUtils.isNotEmpty(number), Orders::getNumber, number);
        lqw.between(beginTime != null && endTime != null, Orders::getOrderTime, beginTime, endTime);
        //查询订单基本信息
        Page<Orders> ordersPage = this.page(pageInfo, lqw);

        //把基本信息拷贝到OrdersDto对象中
        BeanUtils.copyProperties(pageInfo, ordersDtoPage, "records");

        List<Orders> ordersRecords = ordersPage.getRecords();
        List<OrdersDto> ordersDtoList = ordersRecords.stream().map((orderRecord) -> {
            OrdersDto ordersDto = new OrdersDto();
            //拷贝对象
            BeanUtils.copyProperties(orderRecord, ordersDto);
            //获取订单id
            Long orderId = orderRecord.getId();
            //通过订单id查询该订单下对应的菜品/套餐
            LambdaQueryWrapper<OrderDetail> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(OrderDetail::getOrderId, orderId);
            List<OrderDetail> orderDetails = orderDetailService.list(queryWrapper);
            ordersDto.setOrderDetails(orderDetails);

            //根据用户id获取用户名
            Long userId = orderRecord.getUserId();
            User user = userService.getById(userId);
            if (StringUtils.isNotEmpty(user.getName())) {
                ordersDto.setUserName(user.getName());
            }
            return ordersDto;
        }).collect(Collectors.toList());

        ordersDtoPage.setRecords(ordersDtoList);
        return ordersPage;
    }

    /**
     * 功能：将订单数据回显到个人信息页面，以及订单详情页面
     * 需求：
     * 1. 按照订单创建的先后顺序进行排序，list集合会按照加入顺序自动排序
     * 2. 页面中需要展示两表中数据，需要使用 dto 转换对象
     * 3.
     * 实现步骤：
     * 1. 获取当前用户下所有订单数据
     * 1.1 因为数据封装在 Page 对象的 records 属性中，所有先获取 records 属性
     * 1.2 处理 records 集合中数据，将该集合除最后一条数据外全部跳过（也可以使用很多方法，只要能取最后加入集合的元素即可）
     * 2. 新建的 pageInfo 对象中只有 records 属性需要特殊处理，其余属性均可从 ordersDtoPage 对象中复制
     *
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public Page getUserPage(int page, int pageSize) {
        Long currentId = BaseContext.getCurrentId();

        // 获取存有所有订单数据的 page 对象
        Page<Orders> allPage = this.page(new Page<>());
        // 获取到具体存值的集合
        List<Orders> records = allPage.getRecords();

        Page<Orders> pageInfo = new Page<>(page, pageSize);

        // 防止没有订单数据时，长度 -1 下标为负数报错
        if (pageInfo.getRecords().size() > 0) { // 最起码有一条数据
            pageInfo.setRecords(records.stream().skip(records.size() - 1).collect(Collectors.toList()));
        }

        Page<OrdersDto> ordersDtoPage = new Page<>();

        // 获取含有当前用户订单数据的 page 对象（来自数据库）
        LambdaQueryWrapper<Orders> ordersLambdaQueryWrapper = new LambdaQueryWrapper<>();
        ordersLambdaQueryWrapper.eq(Orders::getUserId, currentId);
        Page<Orders> ordersPage = this.page(pageInfo, ordersLambdaQueryWrapper);

        // 复制除 records 之外的所有属性
        BeanUtils.copyProperties(pageInfo, ordersDtoPage, "records");

        List<Orders> ordersList = ordersPage.getRecords();

        // 特殊处理 records 集合
        List<OrdersDto> ordersDtoList = ordersList.stream().map(item -> {
            OrdersDto ordersDto = new OrdersDto();
            BeanUtils.copyProperties(item, ordersDto);
            Long orderId = item.getId();
            if (orderId != null) {
                // 查询订单明细表
                LambdaQueryWrapper<OrderDetail> orderDetailLambdaQueryWrapper = new LambdaQueryWrapper<>();
                orderDetailLambdaQueryWrapper.eq(OrderDetail::getOrderId, orderId);
                List<OrderDetail> orderDetailList = orderDetailService.list(orderDetailLambdaQueryWrapper);
                ordersDto.setOrderDetails(orderDetailList);
            }
            return ordersDto;
        }).collect(Collectors.toList());

        ordersDtoPage.setRecords(ordersDtoList);

        return ordersDtoPage;
    }

    /**
     * 功能：实现用户下单功能
     * 实现：
     * 1. 获取当前登录的 user_id
     * 2. 根据 user_id 查询 shopping_cart 表，即可获取到当前用户的购买信息
     * 3. 查询用户数据，包括联系方式，地址信息等
     * 4. 将购物车中信息，处理后写入 orders 表
     * 5. 向订单明细表中写入数据
     * 6. 下单成功后需要清空购物车
     *
     * @param orders
     */
    @Transactional // 因为需要同时操作多张表，防止提交不同步
    @Override
    public void submitOrder(Orders orders) {

        Long currentId = BaseContext.getCurrentId();

        List<ShoppingCart> carts = shoppingCartService.getCart();

        // 若购物车为空，或是购物车中没有商品，无法下单
        if (carts == null || carts.size() == 0) {
            throw new CustomException("购物车中还没有商品，请先添加商品哦~");
        }

        // 获取当前用户，方便查询用户信息
        User user = userService.getById(currentId);

        // 根据地址 id，获取地址
        Long addressBookId = orders.getAddressBookId();
        AddressBook addressBook = addressBookService.getById(addressBookId);
        // 若该用户无地址信息，无法派送
        if (addressBook == null) {
            throw new CustomException("请先添加收货地址");
        }

        /* 前端传回的订单就已经包含了部分订单信息，但是不全面
         *  包含支付方式，地址编号
         *  其他信息均需要设置
         */
        long orderId = IdWorker.getId(); // IdWorker 是 MP 中提供的工具类，可以生成 id


        /**
         * AtomicInteger 原子操作类，自 JDK1.5 后提供，作用是以原子方式更新的int值
         * 在 java 计算中，如自增，自减等操作，并不是原子性的
         * 在多线程环境下，可能会出现错误
         */
        AtomicInteger amount = new AtomicInteger(0); // 初始值，不写默认是 0

        /*
         * 虽然前端有计算金额，但是没有向后端返回数值
         * 且，前端数据计算是由 js 完成，若遭到前端修改将会造成损失，故后端仍需自己再次计算
         * 计算总金额，遍历购物车集合，做累加
         * 同时，可以生成订单明细的数据
         */
        List<OrderDetail> orderDetails = carts.stream().map((item) -> {
            OrderDetail orderDetail = new OrderDetail(); // 获取订单明细对象
            // 设置订单明细信息
            orderDetail.setOrderId(orderId);
            orderDetail.setNumber(item.getNumber());
            orderDetail.setDishFlavor(item.getDishFlavor());
            orderDetail.setDishId(item.getDishId());
            orderDetail.setSetmealId(item.getSetmealId());
            orderDetail.setName(item.getName());
            orderDetail.setImage(item.getImage());
            orderDetail.setAmount(item.getAmount());
            // 累加的方法
            amount.addAndGet(item.getAmount() // 获取当前价格
                    .multiply(new BigDecimal(item.getNumber())) // 封装过的乘法操作，获取到份数
                    .intValue());
            return orderDetail;
        }).collect(Collectors.toList());

        // 依次设置订单信息
        orders.setId(orderId);
        orders.setOrderTime(LocalDateTime.now());
        orders.setCheckoutTime(LocalDateTime.now());
        orders.setStatus(2); // 下单完成后等待派送，状态 2 表示待派送
        orders.setAmount(new BigDecimal(amount.get())); // 总金额
        orders.setUserId(currentId); // 设置当前用户 id
        orders.setNumber(String.valueOf(orderId));
        orders.setUserName(user.getName());
        orders.setConsignee(addressBook.getConsignee());
        orders.setPhone(addressBook.getPhone());
        // 拼接订单信息
        orders.setAddress((addressBook.getProvinceName() == null ? "" : addressBook.getProvinceName())
                + (addressBook.getCityName() == null ? "" : addressBook.getCityName())
                + (addressBook.getDistrictName() == null ? "" : addressBook.getDistrictName())
                + (addressBook.getDetail() == null ? "" : addressBook.getDetail()));

        // 设置完成后保存，向订单表添加数据
        this.save(orders);

        // 向订单明细表添加数据
        orderDetailService.saveBatch(orderDetails);

        // 清空购物车
        shoppingCartService.clearShoppingCart();

    }
}
